using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace XiVo.PlayThrough
{
  public partial class PlayThroughControl : UserControl
  {
    public PlayThroughControl()
    {
      InitializeComponent();
    }

    public XiVo.PCRComm.ChannelInfo info = new XiVo.PCRComm.ChannelInfo();

    private WaveOutPlayer m_Player;
    private WaveInRecorder m_Recorder;
    private FifoStream m_Fifo = new FifoStream();
    private System.IO.FileStream m_File;
    private System.IO.FileStream m_Info;
    private int BPS;
    private int maxFileSize;
    private long readPos;
    private long writePos;
    bool paused;

    private byte[] m_PlayBuffer;
    private byte[] m_RecBuffer;
    bool bufferToDisk;
    volatile byte[] metaDataBuffer = new byte[128];

    private void Filler(IntPtr data, int size)
    {
      if (m_PlayBuffer == null || m_PlayBuffer.Length < size)
        m_PlayBuffer = new byte[size];

      if (paused)
      {
        for (int i = 0; i < m_PlayBuffer.Length; i++)
          m_PlayBuffer[i] = 0;
      }
      else if (bufferToDisk)
      {

        m_Info.Position = readPos / BPS * XiVo.PCRComm.ChannelInfo.dataBlockSize;
        m_Info.Read(metaDataBuffer, 0, 128);

        m_File.Position = readPos;
        m_File.Read(m_PlayBuffer, 0, size);
        readPos = m_File.Position % maxFileSize;
        long diff = writePos - readPos;
        //if (diff < 0) diff += maxFileSize;
        if (Math.Abs(diff) < size * 2)
          readPos -= size;
      }
      else
      {
        if (m_Fifo.Length >= size)
          m_Fifo.Read(m_PlayBuffer, 0, size);
        else
          for (int i = 0; i < m_PlayBuffer.Length; i++)
            m_PlayBuffer[i] = 0;
      }
      System.Runtime.InteropServices.Marshal.Copy(m_PlayBuffer, 0, data, size);
    }

    private void DataArrived(IntPtr data, int size)
    {
      if (m_RecBuffer == null || m_RecBuffer.Length < size)
        m_RecBuffer = new byte[size];
      System.Runtime.InteropServices.Marshal.Copy(data, m_RecBuffer, 0, size);
      if (bufferToDisk)
      {
        m_Info.Position = writePos / BPS * XiVo.PCRComm.ChannelInfo.dataBlockSize;
        m_Info.Write(info.GetDataBlock(), 0, 128);

        m_File.Position = writePos;
        m_File.Write(m_RecBuffer, 0, m_RecBuffer.Length);
        writePos = m_File.Position % maxFileSize;
      }
      else
        m_Fifo.Write(m_RecBuffer, 0, m_RecBuffer.Length);
    }

    public void Stop()
    {
      StartButton.BackColor = System.Drawing.SystemColors.Control;
      if (m_Player != null)
        try
        {
          m_Player.Dispose();
        }
        finally
        {
          m_Player = null;
        }
      if (m_Recorder != null)
        try
        {
          m_Recorder.Dispose();
        }
        finally
        {
          m_Recorder = null;
        }
      m_Fifo.Flush(); // clear all pending data
    }

    public void Start()
    {
      Stop();
      try
      {
        WaveFormat fmt = new WaveFormat(44100, 16, 2);
        m_Recorder = new WaveInRecorder(-1, fmt, 16384, 3, new BufferDoneEventHandler(DataArrived));
        System.Threading.Thread.Sleep(500);
        m_Player = new WaveOutPlayer(-1, fmt, 16384, 3, new BufferFillEventHandler(Filler));
        StartButton.BackColor = System.Drawing.Color.Red;
      }
      catch
      {
        Stop();
        throw;
      }
    }

    private void StartButton_Click(object sender, System.EventArgs e)
    {
      Start();
    }

    private void StopButton_Click(object sender, System.EventArgs e)
    {
      Stop();
    }

    private void notifyIcon1_Click(object sender, EventArgs e)
    {
    }

    private void startToolStripMenuItem_Click(object sender, EventArgs e)
    {
      Start();
    }

    private void stopToolStripMenuItem_Click(object sender, EventArgs e)
    {
      Stop();
    }

    private void bMoveStart_Click(object sender, EventArgs e)
    {
      readPos = (writePos + BPS) % maxFileSize;
    }

    private void bMoveBack_Click(object sender, EventArgs e)
    {
      readPos -= BPS * 10;
      if (readPos < 0)
        readPos += maxFileSize;
    }

    private void bPause_Click(object sender, EventArgs e)
    {
      paused = !paused;
      if (paused)
        bPause.BackColor = System.Drawing.Color.Red;
      else
        bPause.BackColor = System.Drawing.SystemColors.ButtonFace;
    }

    private void bMoveForward_Click(object sender, EventArgs e)
    {
      readPos = (readPos + BPS * 10) % maxFileSize;
    }

    private void bMoveNow_Click(object sender, EventArgs e)
    {
      readPos = (writePos - BPS) % maxFileSize;
      if (readPos < 0)
        readPos = maxFileSize - BPS;
    }

    private void cbBufferToDisk_CheckedChanged(object sender, EventArgs e)
    {
      bufferToDisk = cbBufferToDisk.Checked;
      if (cbBufferToDisk.Checked)
      {
      }
      else
      {
      }
    }

    private void PlayThroughControl_Load(object sender, EventArgs e)
    {
      BPS = 44100*4;
      maxFileSize = BPS * 60 * 60;

      if (this.DesignMode == false)
      {
        m_File = new System.IO.FileStream("audiodata", System.IO.FileMode.OpenOrCreate);
        m_Info = new System.IO.FileStream("infodata", System.IO.FileMode.OpenOrCreate);
      }

      cbBufferToDisk_CheckedChanged(null, null);
    }

    DateTime GetCurrentTime()
    {
      long difference = ((writePos + maxFileSize - readPos) % maxFileSize);
      difference /= BPS;
      return DateTime.Now.AddSeconds(-difference);
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
      long t = readPos;

      lReadPos.Text = GetCurrentTime().ToLongTimeString();
      lWritePos.Text = writePos.ToString();

      tbChannelNumber.Text = ASCIIEncoding.ASCII.GetString(metaDataBuffer, 0, 8);
      tbChannelName.Text = ASCIIEncoding.ASCII.GetString(metaDataBuffer, 8, 16);
      //genre = ASCIIEncoding.ASCII.GetString(data, 24, 16);
      tbArtist.Text = ASCIIEncoding.ASCII.GetString(metaDataBuffer, 40, 16);
      tbTitle.Text = ASCIIEncoding.ASCII.GetString(metaDataBuffer, 56, 16);
  }
  }
}